import pygame
import sys
import random
# import time
from pygame import gfxdraw

GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLACK = (0, 0, 0)
BLUE = (0, 0, 128)
WID = 800
HEG = 800
FPS = 60
SPEED = 3


# scope1 = 0
# scope2 = 0
score = 0
WALL = pygame.sprite.Group()
TAR = pygame.sprite.Group()
SPRITES = pygame.sprite.Group()

pygame.init()

clock = pygame.time.Clock()
screen = pygame.display.set_mode((WID, HEG))

font = pygame.font.Font('freesansbold.ttf', 16)

sc_wall = font.render('#', 1, BLUE, BLACK)
wall_rect = sc_wall.get_rect(topleft=(0, HEG//2))


def IntersectEndlessLineLine(l1_p1, l1_p2, l2_p1, l2_p2):

    # calculate the line vectors and test if both lengths are > 0
    P = pygame.math.Vector2(*l1_p1)
    Q = pygame.math.Vector2(*l2_p1)
    line1 = pygame.math.Vector2(*l1_p2) - P
    line2 = pygame.math.Vector2(*l2_p2) - Q
    if line1.length() == 0 or line2.length() == 0:
        return (False, (0, 0))

    # check if the lines are not parallel
    R, S = (line1.normalize(), line2.normalize())
    dot_R_nvS = R.dot(pygame.math.Vector2(S[1], -S[0]))
    if abs(dot_R_nvS) < 0.001:
        return (False, (0, 0))

    # calculate the intersection point of the lines
    # t  =  dot(Q-P, (S.y, -S.x)) / dot(R, (S.y, -S.x))
    # X  = P + R * t
    ptVec = Q-P
    t = ptVec.dot(pygame.math.Vector2(S[1], -S[0])) / dot_R_nvS
    xPt = P + R * t
    return (True, (xPt[0], xPt[1]))


def InRange(coord, range_s, range_e):
    if range_s < range_e:
        return coord >= range_s and coord <= range_e
    return coord >= range_e and coord <= range_s


def PtInRect(pt, lp1, lp2):
    return InRange(pt[0], lp1[0], lp2[0]) and InRange(pt[1], lp1[1], lp2[1])


def IntersectLineLine(l1_p1, l1_p2, l2_p1, l2_p2):
    isect, xPt = IntersectEndlessLineLine(l1_p1, l1_p2, l2_p1, l2_p2)
    isect = isect and PtInRect(
        xPt, l1_p1, l1_p2) and PtInRect(xPt, l2_p1, l2_p2)
    return isect, xPt


def IntersectLineRec(p1, p2, rect):
    iL = [
        IntersectLineLine(p1, p2, rect.bottomleft, rect.bottomright),
        IntersectLineLine(p1, p2, rect.bottomright, rect.topright),
        IntersectLineLine(p1, p2, rect.topright, rect.topleft),
        IntersectLineLine(p1, p2, rect.topleft, rect.bottomleft)]
    iDist = [(i[1], pygame.math.Vector2(i[1][0] - p1[0], i[1]
              [1] - p1[1]).length()) for i in iL if i[0]]
    iDist.sort(key=lambda t: t[1])
    return iDist


class Player(pygame.sprite.Sprite):

    def __init__(self, x, y, w, h):
        super().__init__()
        self.w = w
        self.h = h
        self.walls = None
        self.target = None
        self.x = 0
        self.y = 0

        self.image = pygame.Surface([w, h])
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

    def speed(self, x, y):
        self.x += x
        self.y += y

    def update(self):

        if self.rect.x > 0:
            self.rect.x += self.x
        else:
            self.rect.x = 1
        if self.rect.x < WID-self.rect.height:
            self.rect.x += self.x
        else:
            self.rect.x = WID-self.rect.height-1

        if self.rect.y > 0:
            self.rect.y += self.y
        else:
            self.rect.y = 1
        if self.rect.y < HEG-self.rect.height:
            self.rect.y += self.y
        else:
            self.rect.y = HEG-self.rect.height-1

        block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)

        #print(self.rect.x, self.rect.y)

        for block in block_hit_list:
            if self.x > 0:
                self.rect.right = block.rect.left
            elif self.x < 0:
                self.rect.left = block.rect.right
            elif self.y > 0:
                self.rect.bottom = block.rect.top
            elif self.y < 0:
                self.rect.top = block.rect.bottom

        block_hit_tar = pygame.sprite.spritecollide(self, self.target, False)

        for block in block_hit_tar:
            target.draw()


player = Player(0, 0, 10, 10)


class Target(pygame.sprite.Sprite):

    def __init__(self):
        super().__init__()
        self.x = random.randint(1, HEG)
        self.y = random.randint(1, WID)
        self.r = 10

        self.image = pygame.image.load('images/ball_cr.png')
        self.rect = self.image.get_rect(center=(self.x, self.y))

    def draw(self):
        global score
        self.x = random.randint(1, HEG)
        self.y = random.randint(1, WID)
        score += 1
        self.rect = self.image.get_rect(center=(self.x, self.y))


target = Target()
TAR.add(target)
SPRITES.add(TAR)


class Wall(pygame.sprite.Sprite):

    def __init__(self, x, y, w, h):
        pygame.sprite.Sprite.__init__(self)
        self.x = x
        self.y = y
        self.w = w
        self.h = h

        self.image = pygame.Surface((self.w, self.h))
        self.image.fill(BLUE)
        self.rect = pygame.Rect(self.x, self.y, self.w, self.h)
        self.prev_loc = None

    def collision(self, object_location):

        if not self.prev_loc:
            self.prev_loc = object_location
            return None

        intersect = IntersectLineRec(self.prev_loc, object_location, self.rect)
        self.prev_loc = object_location

        if intersect:
            ip = [*intersect[0][0]]
            for i in range(2):
                tp = self.rect.center[i] if ip[i] == object_location[i] else object_location[i]
                ip[i] += -3 if ip[i] < tp else 3
                print(ip)
            self.prev_loc = ip
            return intersect, ip

        return None


wall = Wall(0, HEG//2, 100, 20)
WALL.add(wall)
SPRITES.add(WALL)


pygame.mouse.set_visible(False)
pygame.event.set_grab(True)
loop = True
player.walls = WALL
player.target = TAR
SPRITES.add(player)


while loop:
    keys = pygame.key.get_pressed()

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            loop = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                loop = False
            elif event.key == pygame.K_LEFT:
                player.speed(-SPEED, 0)
            elif event.key == pygame.K_RIGHT:
                player.speed(SPEED, 0)
            elif event.key == pygame.K_UP:
                player.speed(0, -SPEED)
            elif event.key == pygame.K_DOWN:
                player.speed(0, SPEED)

        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT:
                player.speed(SPEED, 0)
            elif event.key == pygame.K_RIGHT:
                player.speed(-SPEED, 0)
            elif event.key == pygame.K_UP:
                player.speed(0, SPEED)
            elif event.key == pygame.K_DOWN:
                player.speed(0, -SPEED)

        elif event.type == pygame.MOUSEMOTION:

            player.rect.center = pygame.mouse.get_pos()
            '''

            collide = wall.rect.colliderect(wall)
            if collide:

                if player.rect.y < wall.rect.y+1:
                    player.rect.bottom = wall.rect.top
                elif player.rect.y > wall.rect.y-1:
                    player.rect.top = wall.rect.bottom
            '''
            intersect_information = wall.collision(pygame.mouse.get_pos())
            if intersect_information:
                intersect, new_location = intersect_information
                pygame.mouse.set_pos(new_location)

    SPRITES.update()
    screen.fill(BLACK)
    SPRITES.draw(screen)

    sc_text = font.render('Score '+str(score), 1, GREEN, BLACK)
    screen.blit(sc_text, (10, 10))

    pygame.display.update()
    clock.tick(FPS)

pygame.quit()
sys.exit()
